package echo.netty.handler_pipeline;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;

/**
 * @author： zhangnan
 * @date： 2025/5/7 16:59
 * @description： TODO
 * @modifiedBy：
 * @version: 1.0
 */
@Slf4j
public class TestPipeline {
    public static void main(String[] args) {
        NioEventLoopGroup boss = new NioEventLoopGroup(1);
        NioEventLoopGroup worker = new NioEventLoopGroup(2);
        new ServerBootstrap()
                .group(boss,worker)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {

                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        // 1. 通过 channel 拿到 pipeline
                        ChannelPipeline pipeline = ch.pipeline();

                        // 用来判断是不是 读空闲时间过长  或  写空闲时间过长  或  其他 读写 空闲时间过长
                        // 单位：秒；参数1：读空闲时间；参数2：写空闲时间；参数3：其他 读写 空闲时间
                        pipeline.addLast(new IdleStateHandler(5,0,0)); // 5S内如果没有收到 channel 的数据，会触发一个 IdleState#READER_IDLE事件
                        



                        // 2. 添加处理器 head(头) -> h1 -> tail(尾)；head和tail都是netty自动加上的
                        // 执行顺序 head(头) -> h1 -> h2 -> h3 -> tail(尾)   是个双向链表
                        pipeline.addLast("h1",new ChannelInboundHandlerAdapter(){
                            @Override
                            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                log.debug("1");
                                super.channelRead(ctx, msg);
                            }
                        });
                        pipeline.addLast("h2",new ChannelInboundHandlerAdapter(){
                            @Override
                            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                log.debug("2");
                                // 如果不调用 channelRead 就不会执行后续的 入站 handler，调用链就会断开
                                super.channelRead(ctx, msg); // 或调用 ctx.fireChannelRead(ctx,msg) 方法
                            }
                        });
                        pipeline.addLast("h3",new ChannelInboundHandlerAdapter(){
                            @Override
                            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                log.debug("3");
//                                super.channelRead(ctx, msg);
                                // 出站处理器执行顺序说明
                                // 只有向channel里写入数据时才能触发 出站处理器 的调用
                                // ch 是从tail也就是从尾巴开始往前找
                                ch.writeAndFlush(ctx.alloc().buffer().writeBytes("server...".getBytes()));
                                // 在这里使用ctx向channel里写数据同样不会触发 出站处理器的调用
                                // 原因：ctx 是从 当前处理器 向 前找 出站处理器，如果有就触发调用
                                // 而上面的 ch 是从tail也就是从尾巴开始往前找
                                ctx.writeAndFlush(ctx.alloc().buffer().writeBytes("server...".getBytes()));
                            }
                        });
                        // 出站顺序是 从后往前传  tail -> h6 -> h5 -> h4
                        pipeline.addLast("h4",new ChannelOutboundHandlerAdapter(){
                            @Override
                            public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
                                log.debug("4");
                                super.write(ctx, msg, promise);
                            }
                        });
                        pipeline.addLast("h5",new ChannelOutboundHandlerAdapter(){
                            @Override
                            public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
                                log.debug("5");
                                super.write(ctx, msg, promise);
                            }
                        });
                        pipeline.addLast("h6",new ChannelOutboundHandlerAdapter(){
                            @Override
                            public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
                                log.debug("6");
                                super.write(ctx, msg, promise);
                            }
                        });
                    }
                })
                .bind(8080);
    }
}
